package com.vdong.redis.data.core.json.ops.impl;

import com.alibaba.fastjson.TypeReference;
import com.vdong.redis.data.core.json.DBExecutor;
import com.vdong.redis.data.core.json.FastJsonRedisTemplate;
import com.vdong.redis.data.core.json.ops.FastJsonValueOperations;
import org.springframework.data.redis.core.ValueOperations;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * ops覆盖类，可提供原先ops没有的方法
* @author <a href="mailto:zhudelie@zuozh.com">zhudelie</a>
* @version 
* @since JDK 1.6
* create on 2017年3月31日
* Copyright 2017 ZZJR All Rights Reserved.
*
*/
public class FastJsonValueOperationsImpl<K,V> extends OperationsAware<K, V> implements FastJsonValueOperations<K,V> {
	private ValueOperations ops;
	public FastJsonValueOperationsImpl(ValueOperations ops, FastJsonRedisTemplate<K,V> template){
		super(template);
		this.ops = ops;
	}
	/**
	 * 设置值
	 */
	
	public void set(K key, V value) {
		// TODO Auto-generated method stub
		ops.set(key, value);
	}
	/**
	 * 设置值，并设置过期时间
	 */
	
	public void set(K key, V value, long timeout, TimeUnit unit) {
		// TODO Auto-generated method stub
		ops.set(key, value, timeout, unit);;
	}
	/**
	 * 设置值，如果当前值为空的话
	 */
	
	public Boolean setIfAbsent(K key, V value) {
		// TODO Auto-generated method stub
		return ops.setIfAbsent(key, value);
	}
	/**
	 * 对多个key设置值
	 */
	
	public void multiSet(Map<? extends K,? extends V> map) {
		ops.multiSet(map);
	}
	/**
	 * 对多个key设置值，如果对应的key没有值的话
	 */
	
	public Boolean multiSetIfAbsent(Map<? extends K,? extends V> map) {
		// TODO Auto-generated method stub
		return ops.multiSetIfAbsent(map);
	}
	/**
	 * 获取值
	 */
	
	public V get(Object key) {
		// TODO Auto-generated method stub
		return (V) ops.get(key);
	}
	/**
	 * 获取值,同时设置一个新值
	 */
	
	public V getAndSet(K key, V value) {
		// TODO Auto-generated method stub
		return (V) ops.getAndSet(key, value);
	}
	/**
	 * 获得多个key的值
	 */
	
	public List<V> multiGet(Collection<K> keys) {
		// TODO Auto-generated method stub
		return ops.multiGet(keys);
	}
	/**
	 * 自增
	 */
	
	public Long increment(K key, long delta) {
		// TODO Auto-generated method stub
		return ops.increment(key, delta);
	}
	/**
	 * 自增
	 */
	
	public Double increment(K key, double delta) {
		// TODO Auto-generated method stub
		return ops.increment(key, delta);
	}
	/**
	 * 追加字符串
	 */
	
	public Integer append(K key, String value) {
		// TODO Auto-generated method stub
		return ops.append(key, value);
	}

	/**
	 * 获得字符串中的一部分
	 */
	public String get(K key, long start, long end) {
		// TODO Auto-generated method stub
		return ops.get(key, start, end);
	}
	/**
	 * 指定的字符串覆盖给定 key 所储存的字符串值，覆盖的位置从偏移量 offset 开始。
	 */
	
	public void set(K key, V value, long offset) {
		ops.set(key, value,offset);
	}
	/**
	 *获得字符串长度
	 */
	
	public Long size(K key) {
		// TODO Auto-generated method stub
		return ops.size(key);
	}
	/**
	 * 对 key 所储存的字符串值，设置或清除指定偏移量上的位(bit)。
	 */
	
	public Boolean setBit(K key, long offset, boolean value) {
		// TODO Auto-generated method stub
		return ops.setBit(key, offset, value);
	}
	/**
	 * 对 key 所储存的字符串值，获得指定偏移量上的位(bit)。
	 */
	
	public Boolean getBit(K key, long offset) {
		// TODO Auto-generated method stub
		return ops.getBit(key, offset);
	}

	
	public void set(K key, V value,DBExecutor<V> db) {
		set(key, value, db, null, null);
	}

	/**
	 * 获得指定类型的值
	 * @param type
	 * @return
	 */
	public <T> T get(K key,Class<T> type) {
		template.setConvertType(type);
		return  (T) get(key);
	}
	public  V get(K key,DBExecutor<V> db) {
		return get(key,db,null,null);
	}
	public  <T> T get(K key,Class<T> type,DBExecutor<T> db) {
		return get(key,type,db,null,null);
	}
	/**
	 *  得到一个list类型的值
	 * @return
	 */
	public List<V> getList(K key){
		template.setConvertType(new TypeReference<List<V>>(){});
		return (List<V>) get(key);
	}
	
	public List<V> getList(K key,DBExecutor<List<V>> db){
		return getList(key,db,null,null);
	}
	/**
	 * 得到一个list类型的值，list里面的元素类型为指定类型
	 * @param type
	 * @return
	 */
	public   <T> List<T> getList(K key,Class<T> type){
		template.setConvertType(new TypeReference<List<T>>(type){});
		return (List<T>) get(key);
	}
	public   <T> List<T> getList(K key,Class<T> type,DBExecutor<List<T>> db){
		return getList(key,type,db,null,null);
	}
	public void set(K key, V value, DBExecutor<V> db,Long timeout, TimeUnit unit) {
		boolean needEx = false;
		if(timeout != null){
			if(unit == null){
				unit = TimeUnit.SECONDS;
			}
			needEx = !template.hasKey(key);
		}
		ops.set(key, value);
		if(needEx){
			template.expire(key, timeout, unit);
		}
		db.execute(key,value);
	}
	
	public  V get(K key, DBExecutor<V> db, Long timeout, TimeUnit unit) {
		V v = get(key);
		if(v == null){
			v = db.execute(key);
			if(v != null){
				set(key, v);
				expire0(key,timeout,unit);
			}
		}
		return (V) v;
	}
	
	
	public <T> T get(K key, Class<T> type, DBExecutor<T> db, Long timeout, TimeUnit unit) {
		T v = get(key,type);
		if(v == null){
			v = db.execute(key,type);
			if(v != null){
				ops.set(key, v);		
				expire0(key, timeout, unit);
			}
		}
		return  v;
	}
	
	public  List<V> getList(K key, DBExecutor<List<V>> db, Long timeout, TimeUnit unit) {
		List<V> list = getList(key);
		if(list == null||list.isEmpty()){
			List list2 = db.execute(key);
			if(list2!=null){
				list = list2;
				if(!list2.isEmpty()){
					ops.set(key, list2);
					expire0(key, timeout, unit);
				}
			}
		}
		return (List<V>) list;
	}
	
	public <T> List<T> getList(K key, Class<T> type, DBExecutor<List<T>> db, Long timeout, TimeUnit unit) {
		List<T> list = getList(key,type);
		if(list == null||list.isEmpty()){
			List list2 = db.execute(key,type);
			if(list2!=null){
				list = list2;
				if(!list2.isEmpty()){
					ops.set(key, list2);
					expire0(key, timeout, unit);
				}
			}
		}
		return list;
	}
	private void expire0(Object key, Long timeout, TimeUnit unit) {
		if(timeout != null){
			if(unit == null){
				unit = TimeUnit.SECONDS;
			}
			template.expire((K) key, timeout, unit);
		}
	}
}
